﻿using System;
using static CyberU;
using static CyberU.UI;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Events;
using System.Collections.Generic;
using Unity.Mathematics;
using Unity.VisualScripting;
using UnityEngine.EventSystems;
using UnityEngine.Serialization;

public class LoopScrollSelector<TItem> : MouseOn where TItem : ClickTextSelectItem
{
    public float itemSwitchAnimationDuration = 0.1f;
    public bool itemSwitchAnimationEnabled = true;
    public float itemGradientAnimationDuration = 0.23f;
    public bool itemGradientAnimationEnabled = true;
    public bool gradientEnabled = true;
    public int defaultTotalShowNum = 9;

    public string _direction = "vertical";
    public string direction
    {
        get
        {
            return _direction;
        }
        set
        {
            if (value == "vertical" && !(layoutGroup is VerticalLayoutGroup))
            {
                DeleteComponent(layoutGroup);
                layoutGroup = gameObject.AddComponent<VerticalLayoutGroup>();
            }
            if (value == "horizontal" && !(layoutGroup is HorizontalLayoutGroup))
            {
                DeleteComponent(layoutGroup);
                layoutGroup = gameObject.AddComponent<HorizontalLayoutGroup>();
            }

            if (value != direction)
            {
                _direction = value;
                foreach (TItem item in items)
                {
                    item.direction = direction;
                }
                UpdatePosition();
                UpdateChildren();
            }
        }
    }

    public bool isVertical
    {
        get
        {
            // return direction=="vertical";
            return (layoutGroup is VerticalLayoutGroup);
        }
    }

    public GameObject scrollSelectorItemPrefab;
    public AutoIndexList<TItem> items = new AutoIndexList<TItem>();
    // public ContentSizeFitter sizeFitter;

    public TItem currentItem
    {
        get { return items[dataIndex]; }
        set
        {
            int idx = items.IndexOf(value);
            if (idx != -1)
            {
                dataIndex = idx;
            }
            else
            {
            }
        }
    }

    public void UpdatePosition(int lastTotalShowNum = 0)
    {
        // Delog($"{upNum}");
        // Delog("updating position ...");
        // float deltaUpNum = upNum - (lastTotalShowNum / 2);
        // Delog($"{deltaUpNum} {upNum} {lastTotalShowNum}");
        // Delog($"{isVertical} {items[0].GetMain()} {deltaUpNum}");
        if (isVertical)
        {
            SetLeft(itemsContainer,0);
            SetTop(itemsContainer,(upNum) * (items[0].GetMain()));
        }
        else
        {
            SetTop(itemsContainer,0);
            SetLeft(itemsContainer,(upNum) * (items[0].GetMain()));
        }
    }

    // public VerticalLayoutGroup verticalLayoutGroup;
    public HorizontalOrVerticalLayoutGroup _layoutGroup;
    public HorizontalOrVerticalLayoutGroup layoutGroup
    {
        get
        {
            return _layoutGroup;
        }
        set
        {
            _layoutGroup=value;
        }
    }

    public RectComponent itemsContainer;
    public void CreateItemsContainer()
    {
        // itemsContainer = new GameObject("itemsContainer");
        // itemsContainer.transform.SetParent(transform, false);
        itemsContainer=AsRectComponent(CreateOrGetGameObject(parent:gameObject, name:"itemsContainer"));
        // MustUsed(itemsContainer.gameObject);
        SetStretch(itemsContainer);
        // SetPosition();
        // itemsContainer = gameObject;
    }
    
    public void SetLayout()
    {
        layoutGroup = GetOrAddComponent<HorizontalOrVerticalLayoutGroup>(itemsContainer);
        // Delog($"vertical {verticalLayoutGroup is null}");
        // verticalLayoutGroup.childAlignment = TextAnchor.UpperLeft;
        layoutGroup.childAlignment = TextAnchor.MiddleCenter;
        layoutGroup.childForceExpandWidth = false;
        layoutGroup.childForceExpandHeight = false;
        layoutGroup.childControlWidth = false;
        layoutGroup.childControlHeight = false;
        layoutGroup.spacing = 0;
        layoutGroup.padding.left = 0;
        layoutGroup.padding.right = 0;
        layoutGroup.padding.top = 0;
        layoutGroup.padding.bottom = 0;
    }
    public void AddMouseScroller()
    {
        SetLayout();
        ScrollWheel mouseScroller = ScrollWheel.Create(parent: itemsContainer, onScroll: (float delta) =>
        {
            if (isExpanded)
            {
                dataIndex -= (int)(delta*10) / 1;
            }
            // Delog(delta);
        });

    }
    public void Awake()
    {
        // Delog(1);
        AddToggle(()=>isExpanded=!isExpanded);
        CreateItemsContainer();
        AddMouseScroller();

        // sizeFitter = _.AddComponent<ContentSizeFitter>();
        // sizeFitter.horizontalFit = ContentSizeFitter.FitMode.PreferredSize;
        // sizeFitter.verticalFit = ContentSizeFitter.FitMode.PreferredSize;
    }

    public virtual void ConfirmSelected()
    {
        if (dataIndex == lastDataIndex)
        {
            AfterRepeatSelected();
        }
        else
        {
            AfterNewItemSelected();
        }
    }
    public virtual void AfterNewItemSelected()
    {
    }

    public virtual void AfterRepeatSelected()
    {
    }

    public void switchIndex(int index)
    {
        this.dataIndex = index;
    }


//位于上侧的条目数，包括没展示的
    public int upNum
    {
        get { return totalShowNum / 2; }
        set
        {
            totalShowNum = value * 2 + 1;
            upNum = value;
        }
    }

    public int n;

    public float[] alphas;

    private int _totalShowNum;

    public int totalShowNum
    {
        get { return _totalShowNum; }
        set
        {
            if (_totalShowNum != value)
            {
                int __totalShowNum=_totalShowNum;
                _totalShowNum = value;
                updateAlphas();
                UpdatePosition(__totalShowNum);
                UpdateChildren();
            }
        }
    }

    void updateAlphas()
    {
        alphas = new float[upNum + 1];
        for (int i = 0; i <= upNum; i++)
        {
            alphas[i] = (float)(upNum + 1 - i) / (upNum + 1);
        }
    }

    public int _dataIndex;
    public int dataIndex
    {
        get { return _dataIndex; }
        set
        {
            // Delog($"dataIndex set {value}");
            if (_dataIndex != value)
            {
                lastSwitchedChildIndex = GetSiblingIndex(items[value]);
                lastDataIndex = _dataIndex;
                _dataIndex = value;
                // Delog($"check lastIndex. {lastIndex} {_dataIndex}");
                UpdateChildren();
            }
            else
            {
                lastSwitchedChildIndex = GetSiblingIndex(items[value]);
                lastDataIndex = _dataIndex;
                _dataIndex = value;
                // Delog($"switched the same {value}");
                // AfterRepeatSelected();
            }
            // Delog(items[value].gameObject.isActiveAndEnabled());
        }
    }

    public int lastDataIndex;

    public int lastSwitchedChildIndex;

    public int ChildIndex2DataIndex(int index)
    {
        return transform.GetComponentsInChildren<TItem>()[index].dataIndex;
    }

    public int length
    {
        get { return Math.Max(n, totalShowNum); }
    }

    public int DataIndex2ChildIndex(int index)
    {
        return items[index].transform.GetSiblingIndex();
    }

    public void InitPaint()
    {
        UpdateChildren();
    }

    
    bool IsItemTransitBorder(int newChildIndex)
    {
        bool ret;
        if (lastSwitchedChildIndex < upNum)
        {
            // return newChildIndex<upNum-lastSwitchedChildIndex;
            ret = newChildIndex < upNum - lastSwitchedChildIndex;
        }
        else
        {
            // return n-newChildIndex<lastSwitchedChildIndex-upNum;
            ret = n - newChildIndex - 1 < lastSwitchedChildIndex - upNum;
        }

        // Delog($"{ret} {newChildIndex}");
        // Delog($"{n - newChildIndex-1} {lastSwitchedChildIndex-upNum}");
        return ret;
    }
    public void UpdateChildren()
    {
        if (totalShowNum > n)
        {
            Debug.LogError("not enough n");
        }
        int newChildIndex = 0;
        for (int i = _dataIndex - upNum; i < _dataIndex + n - upNum; i++)
        {
            // Delog($"{items[i].lastChildIndex}");
            items[i].childIndex = newChildIndex;
            bool isItemTransitBorder = IsItemTransitBorder(newChildIndex);
            SetVisible(component: items[i], alpha: DataIndex2Alpha(i), animation: UI.useAnimation && itemGradientAnimationEnabled && (newChildIndex != upNum)&&(!isItemTransitBorder), duration: itemGradientAnimationDuration);
            SetChildIndex(index: newChildIndex, oldIndex: items[i].lastChildIndex, component: items[i], parent: itemsContainer, animation: UI.useAnimation && itemSwitchAnimationEnabled, fromOuterLikeLoop: isItemTransitBorder, duration: itemSwitchAnimationDuration, n: n);
            // Delog($"set alpha {CountAlpha(i)} to position {newIndex}");
            // Delog($"{newIndex} {i} {index}");
            // Delog(n);
            newChildIndex++;
        }
    }

    public float DataIndex2Alpha(int _dataIndex)
    {
        if (totalShowNum > n)
        {
            Debug.LogError("not enough n");
            return 0;
        }
        else
        {
            if (!gradientEnabled)
            {
                return 1;
            }

            if (isExpanded)
            {
                int i = Math.Abs(dataIndex - _dataIndex);
                if (i > alphas.Length - 1)
                {
                    return 0;
                }

                // Delog($"i is {i}, {alphas[i]}");
                return alphas[i];
            }
            else
            {
                // Delog($"{totalShowNum} {upNum}");
                return dataIndex == _dataIndex ? 1f : 0f;
            }
        }
    }

    public void Start()
    {
        // Delog("scrollSelector created");
        // ShowRect(color: Color.yellow, gameObject: gameObject);
        // AddShadowBackground(gameObject);
        // gameObject.AddComponent<RectTransform>();
        // totalShowNum = defaultTotalShowNum;
        totalShowNum = defaultTotalShowNum;
        lastSwitchedChildIndex = upNum;
        InitPaint();
        // if (items.Count > 0)
        // {
        // SetCurrentItem(items[0]);
        // }
    }

    public TItem AddItem(string name, TItem item)
    {
        n += 1;
        // Delog($"item is null: {item} verticalLayoutGroup is null: {verticalLayoutGroup}");
        // Delog($"item.rectTransform is null: {GetRectTransform(component:item)}, ");
        // Delog($"added {item}");
        SetParent(item, itemsContainer);
        if (isVertical)
        {
            item.height = itemsContainer.height;
        }
        else
        {
            item.width = itemsContainer.width;
        }
        // item.transform.SetParent(verticalLayoutGroup.transform, false);
        // Delog(direction);
        items.Add(item);
        item.name = name;
        int _ = n - 1;
        item.AddClickListener(() =>
        {
            // lastIndex = item.index;
            dataIndex = _;
            ConfirmSelected();
        });
        SetAsItemSize(item);
        item.dataIndex = item.lastDataIndex = _;
        item.lastChildIndex = _;
        item.childIndex = _;
        item.direction = direction;
        return item;
    }
    
    public void ClearItem()
    {
        for (int i = 0; i < n; i++)
        {
            DeleteItem(n - 1 - i);
        }
    }

    private void RemoveItem(int index)
    {
        DeleteItem(index);
    }
    private void DeleteItem(int index)
    {
        TItem item =items.Pop(index);
        Destroy(item.gameObject);
    }


    public TItem Add(string name, TItem item)
    {
        // Delog($"gameObject is null: {gameObject}");
        // Delog($"adding {name}");
        return AddItem(name: name, item: item);
    }


    public void SetAsItemSize(TItem item)
    {
        // layoutElement = GetOrCreate<LayoutElement>(gameObject);
        // layoutElement = GetOrCreate<LayoutElement>(gameObject);
        RectTransform itemRectTransform = item.gameObject.GetComponent<RectTransform>();
        Vector2 size = itemRectTransform.rect.size;
        // Delog($"item size (and layoutElement size) {size}");
        // Delog($"{layoutElement} | {Used(size)}");
        // layoutElement.minWidth = size.x;
        // layoutElement.minHeight = size.y;
        // DirectlySetSize(gameObject, x:size.x, y :size.y);
    }


    public void SetCurrentItem(TItem item)
    {
        currentItem = item;
    }

    public bool _isExpanded;

    public bool isExpanded
    {
        get { return _isExpanded; }
        set
        {
            if (value != _isExpanded)
            {
                // Delog("isExpand change");
                _isExpanded = value;
                if (gradientEnabled)
                {
                    UpdateChildren();
                }
            }
        }
    }

    
}